#pragma once
#include "buffer.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include<memory>
namespace logs
{
    enum class loopersafe
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE,
    };
    class Asynclooper
    {
    public:
        using ptr = std::shared_ptr<Asynclooper>;
        using Functor = std::function<void(buffer&)>;
        Asynclooper(Functor factor, loopersafe safe = loopersafe::ASYNC_SAFE)
            :_callback(factor)
            ,_stop(false)
            ,_safe(safe)
            ,_thread(std::thread(&Asynclooper::threadRun,this))
        {
            ;
        }
        ~Asynclooper()
        {
            stop();
        }
        void push(const char *dst, size_t len)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex); // 加锁访问缓冲区
                if(_safe == loopersafe::ASYNC_SAFE)
                    _pro_condition.wait(lock,[&](){return _pro_buffer.WriteAbleSize() >= len;});
                _pro_buffer.push(dst, len);
            }
            _con_condition.notify_all();
        }
        void threadRun()
        {
            while(1)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex); // 加锁访问缓冲区
                    if(_stop && _pro_buffer.empty())//有时候可能刚交换完缓冲区,_stop就被设为true，然后任务缓冲区数据就丢了
                        break;
                    //看看生产缓冲区是否为空,不为空以及工作器被停止了都应该往下继续走
                    _con_condition.wait(lock,[&](){return _stop || !_pro_buffer.empty();});
                    _con_buffer.swap(_pro_buffer);//交换       
                }
                if(_safe == loopersafe::ASYNC_SAFE)
                    _pro_condition.notify_all();
                _callback(_con_buffer);//处理消费缓冲区内的数据
                _con_buffer.reset();//重置消费缓冲区
            }
        }
        void stop()
        {
            _stop = true;
            _con_condition.notify_all();
            _thread.join();
        }
    private:
        // 双缓冲区
        bool _stop;
        loopersafe _safe;
        Functor _callback;
        logs::buffer _pro_buffer;
        logs::buffer _con_buffer;
        std::mutex _mutex;
        std::condition_variable _pro_condition;
        std::condition_variable _con_condition;
        std::thread _thread;//异步工作器对应的线程
    };
};